package com.swdegao.iot.netty.udp.server.guoxinudp;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.UUID;

import com.swdegao.iot.netty.entity.*;
import com.swdegao.iot.netty.utils.*;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.alibaba.fastjson.JSON;
import com.swdegao.iot.SwdegaoIotMgtServerApplication;
import com.swdegao.iot.netty.service.impl.TerminalsServiceImpl;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 * @Author:zt
 * @Date: Created in 8:20 2018\10\26 0002
 */

// public class ParseMessgaeHandler extends
// SimpleChannelInboundHandler<DatagramPacket>{
public class GuoXinUdpParseMessgaeHandler extends SimpleChannelInboundHandler<DatagramPacket> {
	// 定义一个全局的记录器，通过LoggerFactory获取
	private final static Logger logger = LoggerFactory.getLogger(GuoXinUdpParseMessgaeHandler.class);
	//static ExecutorService executorService = Executors.newFixedThreadPool(1);

	@Autowired
	private RedisUtils redisUtils = SwdegaoIotMgtServerApplication.getBean(RedisUtils.class);
	static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

	private HandlerMessage hm = new HandlerMessage();
	@Autowired
	private TerminalsServiceImpl ts = SwdegaoIotMgtServerApplication.getBean(TerminalsServiceImpl.class);

	@SuppressWarnings("unused")
	private String tempTime = null;// 用于比较心跳是否超时
	private Boolean flag = true;
	boolean is_waitingpresetcommand = false;//是否等待预置命令返回

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { // (4)

		// Channel channel = ctx.channel();
		// logger.info("UDP服务器收到客户端消息");
		// DatagramPacket dp = (DatagramPacket)msg;
		ByteBuf in = msg.content();
		String clintdata=ByteBufUtil.hexDump(in).toUpperCase();
		logger.info(clintdata);
		byte[] barray = new byte[in.readableBytes()];
		in.getBytes(0, barray);

		ByteBuf bodyAll = in.duplicate();

		// ByteBuf bodyAll = in;
		String ChannelID = null;
		try {
			if (GuoXinUDPConst.HEAD.equals(in.getByte(0))) {// 验证帧头:0x80
				ChannelID = GuoXinUdpDataResction.ResctionADDStr(in);

				// 更换连接ID
				if (!GuoXinUDPConst.hasChannelID(ChannelID)) {
					String realChannelID = GuoXinUDPConst.isChannel(ctx.channel());
					// logger.info("!GuoXinUDPConst.hasChannelID,realChannelID "
					// +realChannelID);
					GuoXinUDPConst.ChangeClientId(realChannelID, ChannelID);
					// 记录上线记录
					onoffLineAction(ChannelID, Parameter.online_des, 1);// 记录上线
					onoffLineForCenter(ChannelID, 1);
				}
				// 检查重复链接ID 不同实例 切换实例
				if (GuoXinUDPConst.ischangeChannelID(ChannelID, ctx.channel())) {
					logger.info("GuoXinUDPConst.ischangeChannelID,ChannelID " + ChannelID);
					GuoXinUDPConst.changeChannel(ChannelID, ctx.channel());
					// 记录重复上线记录
					onoffLineAction(ChannelID, Parameter.reonline_des, 0);// 记录下线
					onoffLineForCenter(ChannelID, 0);
				}
				// 数据域
				//ByteBuf recevieMsg = Unpooled.wrappedBuffer(GuoXinUdpDataResction.ResctionBody(bodyAll));
				// 数据类型:0x81,0x82,0x83,0x84
				//Byte type = GuoXinUdpDataResction.ResctionDataType(in.getByte(3));
				//hm.setActionTpye(type);
				hm.setImei(ChannelID);
				hm.setRecevieMsgStr(ByteBufUtil.hexDump(in).toUpperCase());
				// logger.info("UDP客户端IMEI:"+ ChannelID);
				hm.setSendMsg(GetSuccessSignal(in));
				//ctx.writeAndFlush(new DatagramPacket(Unpooled.wrappedBuffer(GetSuccessSignal(in)).retain(),msg.sender()));
				ctx.writeAndFlush(new DatagramPacket(hm.getSendMsg().retain(),msg.sender()));


				try {
					//进入预置命令发送模式
					if(redisUtils.exists(ChannelID+Parameter.imei_waitingpresetcommand)){

						long nowtime = System.currentTimeMillis();
						PresetCommand presetCommand = JSON.parseObject(redisUtils.index(ChannelID+Parameter.imei_waitingpresetcommand, 0).toString(),PresetCommand.class);
						//接受预置命令处理成功逻辑
						if(is_waitingpresetcommand){
							int OutTime = Parameter.outtime_hear;

							Long differenceTime = (nowtime - presetCommand.getActiontime()) / 1000 - OutTime;
							if (differenceTime > 0) {//问题已经过期、将hash中Imei_info更新、下次无需再验证问题失效逻辑
								is_waitingpresetcommand = true;
							}else{
								//没有过时，处理成功
								redisUtils.removeValue(ChannelID+Parameter.imei_waitingpresetcommand, 1, JSON.toJSONString(presetCommand));//删除imei_waitingpresetcommand
								presetCommand.setActiontime(nowtime);
								presetCommand.setStatus(Parameter.imei_presetcommand_status_ok);
								redisUtils.lPush(ChannelID+Parameter.imei_presetcommand, JSON.toJSONString(presetCommand));//添加到imei_presetcommand
							}
						}
						//发送预置命令逻辑
						if(!is_waitingpresetcommand) {
							if (Parameter.presetCommandNum.equals(presetCommand.getNum())) {
								//已经达到预置命令重发上线,删除imei_waitingpresetcommand，添加imei_presetcommand
								redisUtils.removeValue(ChannelID + Parameter.imei_waitingpresetcommand, 1, JSON.toJSONString(presetCommand));//删除imei_waitingpresetcommand
								presetCommand.setStatus(Parameter.imei_presetcommand_status_error);
								redisUtils.lPush(ChannelID + Parameter.imei_presetcommand, JSON.toJSONString(presetCommand));//添加到imei_presetcommand
								presetCommand = redisUtils.exists(ChannelID + Parameter.imei_waitingpresetcommand) ? JSON.parseObject(redisUtils.index(ChannelID + Parameter.imei_waitingpresetcommand, 0).toString(), PresetCommand.class) : null;
								is_waitingpresetcommand = false;
							}

							//发送预置命令
							if (null != presetCommand) {
								//没有达到预置命令重发上线,num+1
								//Thread.sleep(10);
								//cxt.writeAndFlush(GetPresetCommand(imei,presetCommand));
								ctx.writeAndFlush(new DatagramPacket(Unpooled.wrappedBuffer(Hex.decodeHex(presetCommand.getDownData())).retain(),msg.sender()));
								is_waitingpresetcommand = false;
								redisUtils.removeValue(ChannelID + Parameter.imei_waitingpresetcommand, 0, JSON.toJSONString(presetCommand));//删除imei_waitingpresetcommand
								//redisUtils.set(ChannelID + Parameter.imei_waitingpresetcommand, 0, JSON.toJSONString(presetCommand));//更新imei_waitingpresetcommand
								presetCommand.setStatus(Parameter.imei_presetcommand_status_ok);
								redisUtils.lPush(ChannelID + Parameter.imei_presetcommand, JSON.toJSONString(presetCommand));//添加到imei_presetcommand
							}

						}

					}
				} catch (Exception e) {
					// TODO: handle exception
					logger.error(ChannelID+"#######--预置命令"+e.getMessage());
				}

				ctx.fireChannelRead(hm);
			} else {
				logger.info("验证帧头:0x80--不通过");
				// 验证不通过关闭channel
				// ctx.writeAndFlush(CallBackMessage.ERROR.duplicate());
				// ctx.close();
			}
		} catch (Exception e) {
			logger.error(ChannelID + e.getMessage());
		} finally {
			// ReferenceCountUtil.release(in);
			// logger.error(ChannelID+"ParseMessgaeHandlerfinally");
		}
	}

	@Override
	public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
		// TODO Auto-generated method stub
		super.channelRegistered(ctx);
		// System.out.println("创建连接");
		logger.info("创建UDP连接");
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)
		logger.info("UDP通道已经连接");
		GuoXinUDPConst.add(String.valueOf(UUID.randomUUID()), ctx.channel());
		channels.add(ctx.channel());
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)
		String channelId = GuoXinUDPConst.getChannelIds(ctx.channel());

		if (!"".equals(channelId) && channelId.indexOf("_") == -1) {
			onoffLineAction(channelId, Parameter.offline_des, 0);// 记录下线
			onoffLineForCenter(channelId, 0);
			// 清掉redis中关于心跳记录
			// ImeiInfo imeiInfo =
			// JSON.parseObject(redisUtils.hmGet(Parameter.imei_info,channelId).toString(),
			// ImeiInfo.class);
			// imeiInfo.setHeartbeat_delay_num(0);
			// imeiInfo.setHeartbeat_registered_num(0);
			// redisUtils.hmSet(Parameter.imei_info, channelId,
			// JSON.toJSONString(imeiInfo));
		}
		// GuoXinUDPConst.remove(ctx.channel());
		logger.info("UDP通道已经关闭");
		// channels.remove(ctx.channel());
		// 记录下线
		// logger.info("Disconnected client " + ctx.channel().remoteAddress() +
		// "掉线" + channelId);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (7)
		Channel incoming = ctx.channel();
		logger.info("client " + incoming.remoteAddress() + "异常" + cause.getMessage());
		// 当出现异常就关闭连接
		cause.printStackTrace();
		ctx.close();
	}

	/**
	 * 上线操作
	 *
	 * @param imei
	 * @param
	 */
	private void onoffLineAction(String imei, String type, int status) {
		OnOffData onOff = new OnOffData();
		onOff.setImei(imei);
		onOff.setCreatetime(System.currentTimeMillis());
		onOff.setAction(type);
		redisUtils.lPush(imei + Parameter.on_off_info, JSON.toJSONString(onOff));// 存储所有updata数据
	}

	/**
	 * 上线下线操作
	 *
	 * @param imei
	 * @param
	 */
	@SuppressWarnings("unused")
	private void onoffLineForCenter(String imei, int status) {
		Terminals terminal = new Terminals();
		terminal.setImei(imei);
		terminal.setOnlinestatus(status);
		// ts.updateTerminalOnlineStatus(terminal);
	}

	public String getTimeNow() {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		return df.format(new Date());
	}

	/**
	 * 获取超时时间
	 *
	 * @param timeNow
	 */
	public String getTimeOut(String timeNow) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Calendar cal = new GregorianCalendar();

		try {
			cal.setTime(df.parse(timeNow));
			cal.add(Calendar.SECOND, Parameter.outtime_hear);

		} catch (ParseException e) {
			e.printStackTrace();
		}
		return df.format(cal.getTime());
	}

	/**
	 * 比较超时时间，是否超时
	 */
	public int CompareOutTime(String timeNow, String timeAfter, SimpleDateFormat timestampFormat) {
		if (timeNow.equals(timeAfter)) // same
			return 1;
		try {
			Date timesN = timestampFormat.parse(timeNow);
			Date timesA = timestampFormat.parse(timeAfter);
			if (timesA.after(timesN)) // time 1 is newer
				return 1;
			else
				return -1;
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return 1;
	}

	/**
	 *
	 * @param imei
	 * @param type
	 * @return
	 */
	public ByteBuf ToDeviceClockMsg(String imei, byte type) {
		SimpleDateFormat df = new SimpleDateFormat("yyMMddHHmmss");
		String date = df.format(new Date());
		byte[] temp2_ = ConvertUtils.getDateFromStr(date, 6);
		byte[] msg = new byte[22 + temp2_.length];
		msg[0] = (byte) 0x80;
		msg[1] = 0x28;
		msg[2] = 0;
		msg[3] = type;

		byte[] temp = imei.getBytes();
		System.arraycopy(temp, 0, msg, 4, 15);// 类型、imei

		// byte[] temp = ConvertUtils.getByte(Integer.parseInt(imei), 15);
		// System.arraycopy(temp, 0, msg, 4, 15);
		System.arraycopy(temp2_, 0, msg, 19, 6);
		msg[msg.length - 3] = ConvertUtils.getTotalForByte(msg);
		msg[msg.length - 2] = 0x0d;
		msg[msg.length - 1] = 0x0a;
		return Unpooled.wrappedBuffer(msg);
	}

	public ByteBuf GetSuccessSignal(ByteBuf recevieMsg) {
		byte[] receiveMsgBytes = new byte[recevieMsg.capacity()];
		recevieMsg.getBytes(recevieMsg.readerIndex(), receiveMsgBytes);

		byte[] msg = new byte[23];
		msg[0] = (byte) 0xc0;
		msg[1] = 0x42;

		System.arraycopy(receiveMsgBytes, 2, msg, 2, 15);// 地址 功能码 设备类型---消息ID
		msg[17] = 0x02;// 长度
		msg[19] = 0x13;// 信息版本
		msg[20] = 0x00;// 控制码
		msg[21] = ConvertUtils.getTotalForByte(msg);// 校验和
		msg[22] = (byte)0xd0;
		//msg[22] = 0x0a;

		//return msg;
		return Unpooled.wrappedBuffer(msg);
	}


}
